package com.ego.service.impl;

import com.ego.client.BrandFeignClient;
import com.ego.client.CategoryFeignClient;
import com.ego.client.GoodsFeignClient;
import com.ego.exception.EgoException;
import com.ego.exception.ExceptionEnum;
import com.ego.pojo.Brand;
import com.ego.pojo.Category;
import com.ego.pojo.Sku;
import com.ego.pojo.SpuDetail;
import com.ego.pojo.bo.SpuBo;
import com.ego.pojo.utils.JsonUtils;
import com.ego.service.GoodsService;
import com.ego.utils.ThreadUtils;
import com.fasterxml.jackson.core.type.TypeReference;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;

import javax.annotation.Resource;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.*;

/**
 * @author Ares
 * @date 2020-12-4
 */
@Service
@Slf4j
public class GoodsServiceImpl implements GoodsService {

    @Resource
    private BrandFeignClient brandFeignClient;

    @Resource
    private CategoryFeignClient categoryFeignClient;

    @Resource
    private GoodsFeignClient goodsFeignClient;

    @Resource
    private TemplateEngine templateEngine;

    @Override
    public Map<String, Object> loadModel(Long spuId) {
        SpuBo spuBo = goodsFeignClient.queryGoodsById(spuId);
        SpuDetail spuDetail = spuBo.getSpuDetail();
        List<Sku> skus = spuBo.getSkus();
        List<Long> ids = new ArrayList<>();
        ids.add(spuBo.getCid1());
        ids.add(spuBo.getCid2());
        ids.add(spuBo.getCid3());
        List<Category> categories = categoryFeignClient.selectByIds(ids).getBody();
        Brand brand = brandFeignClient.selectByIds(Collections.singletonList(spuBo.getBrandId())).getBody().get(0);
        String specifications = spuDetail.getSpecifications();
        List<Map<String, Object>> maps = JsonUtils.nativeRead(specifications, new TypeReference<List<Map<String, Object>>>() {
        });
        Map<Integer, String> specName = new HashMap<>();
        Map<Integer, Object> specValue = new HashMap<>();
        getAllSpec(maps, specName, specValue);
        String specTemplate = spuDetail.getSpecTemplate();
        Map<String, String[]> specs = JsonUtils.nativeRead(specTemplate, new TypeReference<Map<String, String[]>>() {
        });
        Map<Integer, String> specialParamName = new HashMap<>();
        Map<Integer, String[]> specialParamValue = new HashMap<>();
        getSpecialSpec(specs, specName, specValue, specialParamName, specialParamValue);

        List<Map<String,Object>> groups = this.getGroupsSpec(maps,specName,specValue);
        Map<String,Object> map = new HashMap<>();
        map.put("spu",spuBo);
        map.put("spuDetail",spuDetail);
        map.put("skus",skus);
        map.put("brand",brand);
        map.put("categories",categories);
        map.put("specName",specName);
        map.put("specValue",specValue);
        map.put("groups",groups);
        map.put("specialParamName",specialParamName);
        map.put("specialParamValue",specialParamValue);
        return map;

    }

    @Override
    public void createHtml(Long spuId) {
        PrintWriter writer = null;
        Map<String, Object> map = loadModel(spuId);
        Context context = new Context();
        context.setVariables(map);
        File file = new File("D:\\nginx-1.8.0\\html\\item\\" + spuId + ".html");
        try {
            writer = new PrintWriter(file);
            templateEngine.process("item",context,writer);
        } catch (FileNotFoundException e) {
            EgoException.error(log, ExceptionEnum.CREATE_STATIC_PAGE_ERROR,e);
            e.printStackTrace();
        } finally {
            if(writer!=null){
                writer.close();
            }
        }
    }

    /**
     * 新建线程处理页面静态化
     * @param spuId
     */
    @Override
    public void asyncExecute(Long spuId) {
        ThreadUtils.execute(() ->createHtml(spuId));
    }

    @Override
    public void deleteHtml(Long id) {
        File file = new File("D:\\nginx-1.8.0\\html\\item\\", id + ".html");
        file.delete();

    }


    private void getAllSpec(List<Map<String, Object>> specs, Map<Integer, String> specName, Map<Integer, Object> specValue) {
        String k = "k";
        String v = "v";
        String unit = "unit";
        String numerical = "numerical";
        String options = "options";
        int i = 0;
        if (specs != null) {
            for (Map<String, Object> spec : specs) {
                List<Map<String, Object>> params = (List<Map<String, Object>>) spec.get("params");
                for (Map<String, Object> param : params) {
                    String result = null;
                    if (param.get(v) == null) {
                        result = "无";
                    } else {
                        result = param.get(v).toString();
                    }
                    if (param.containsKey(numerical) && (boolean) param.get(numerical)) {
                        if (result.contains(".")) {
                            Double d = Double.valueOf(result);
                            if (d.intValue() == d) {
                                result = d.intValue() + "";
                            }
                        }
                        i++;
                        specName.put(i, param.get(k).toString());
                        specValue.put(i, result + param.get(unit).toString());
                    } else if (param.containsKey(options)) {
                        i++;
                        specName.put(i, param.get(k).toString());
                        specValue.put(i, param.get(options));
                    } else {
                        i++;
                        specName.put(i, param.get(k).toString());
                        specValue.put(i, param.get(v));
                    }
                }
            }
        }
    }

    private void getSpecialSpec(Map<String, String[]> specs, Map<Integer, String> specName, Map<Integer, Object> specValue, Map<Integer, String> specialParamName, Map<Integer, String[]> specialParamValue) {
        if (specs != null) {
            for (Map.Entry<String, String[]> entry : specs.entrySet()) {
                String key = entry.getKey();
                for (Map.Entry<Integer, String> stringEntry : specName.entrySet()) {
                    if (stringEntry.getValue().equals(key)) {
                        specialParamName.put(stringEntry.getKey(), stringEntry.getValue());
                        String s = specValue.get(stringEntry.getKey()).toString();
                        String result = StringUtils.substring(s, 1, s.length() - 1);
                        specialParamValue.put(stringEntry.getKey(), result.split(","));
                    }
                }
            }
        }
    }

    private List<Map<String, Object>> getGroupsSpec(List<Map<String, Object>>
                                                            allSpecs, Map<Integer, String> specName, Map<Integer, Object> specValue) {
        List<Map<String, Object>> groups = new ArrayList<>();
        int i = 0;
        int j = 0;
        for (Map<String, Object> spec : allSpecs) {
            List<Map<String, Object>> params = (List<Map<String, Object>>)
                    spec.get("params");
            List<Map<String, Object>> temp = new ArrayList<>();
            for (Map<String, Object> param : params) {
                for (Map.Entry<Integer, String> entry : specName.entrySet()) {
                    if (entry.getValue().equals(param.get("k").toString())) {
                        String value = specValue.get(entry.getKey()) != null ?
                                specValue.get(entry.getKey()).toString() : "无";
                        Map<String, Object> temp3 = new HashMap<>(16);
                        temp3.put("id", ++j);
                        temp3.put("name", entry.getValue());
                        temp3.put("value", value);
                        temp.add(temp3);
                    }
                }
            }
            Map<String, Object> temp2 = new HashMap<>(16);
            temp2.put("params", temp);
            temp2.put("id", ++i);
            temp2.put("name", spec.get("group"));
            groups.add(temp2);
        }
        return groups;
    }
}
